#__Author:Administrator
#__Date:2019/7/23
import socketserver
import os
import sys
import pickle
from lib import commons
from config import setting
import subprocess
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
#sys.path.append(BASE_DIR)

class MultiServerHandler(socketserver.BaseRequestHandler):
    def handle(self):
        #while True:
        conn = self.request
        conn.sendall(bytes("欢迎登录", encoding="utf-8"))
        obj = Action(conn)
        while True:
            client_bytes = conn.recv(1024)
            if not client_bytes:
                break
            client_str = str(client_bytes, encoding="utf-8")
            action = client_str.split(" ", 1)
            #用户注册
            if obj.login_status:  #判断是否已经登录
                if len(action) > 0:
                    func = getattr(obj, action[0]) #反射，根据客户端输入的指令执行相应的函数
                    func(client_str)
                else:
                    conn.sendall(bytes("输入的格式有错误", encoding="utf-8"))
            elif action[0] == "useradd":
                conn.sendall(bytes("4006", encoding="utf-8"))
                pwd = str(conn.recv(1024), "utf-8")
                obj1 = useradd(action[1], pwd)
                conn.sendall(bytes(obj1.status, encoding="utf-8"))
                continue
            else:
                obj.login(client_str)  #调用登录方法
        conn.close()

class MultiServer():
    def __init__(self):
        self.server = socketserver.ThreadingTCPServer((setting.BIND_HOST, setting.LISTEN_PORT), MultiServerHandler)
        self.server.serve_forever()

class BaseModel:
    """
    公共类
    """
    def save(self):
        """
        保存对象信息
        :return:
        """
        nid = str(self.nid)
        file_path = os.path.join(setting.DB_DIR, nid)
        if not os.path.exists(setting.DB_DIR):
            os.makedirs(setting.DB_DIR)
        pickle.dump(self, open(file_path, 'wb'))

    def nid(self):
        #为用户分配置id，用于保存对象信息
        return commons.create_uuid()

class useradd(BaseModel):
    def __init__(self, user, pwd):
        self.nid = self.nid()
        self.re_status = None
        self.user = user
        self.pwd = pwd
        self.home = os.path.join(setting.USER_HOME, self.user)
        obj = Action.get_all_user()
        for i in obj:
            if i.user == self.user:
                self.re_status = "4005"
                break
        else:
            self.save()
            if not os.path.isdir(self.home):
                os.mkdir(self.home)
            self.re_status = "4004"
    @property
    def status(self):
        return self.re_status

class Action(object):
   # db_path = setting.BD_DIR
    def __init__(self, conn):
        self.conn = conn
        self.login_status = False
        self.username = None
        self.home = None
        self.current_dir = None

    def login(self, client_str):
        """
        :param client_str: 客户端发回来的信息
        :return:
        """
        condit = True
        self.conn.sendall(bytes("4001", encoding='utf-8'))
        print(client_str)
        while condit:
            client_str = self.conn.recv(1024)
            user_info = str(client_str, encoding="utf-8")
            user, pwd = user_info.split(" ")
            obj = Action.get_all_user()
            for i in obj:
                if i.user == user and i.pwd == pwd:
                    self.login_status = True
                    self.username = user
                    self.initialize()
                    self.conn.sendall(bytes("4002", 'utf-8'))
                    condit = False
                    break
            else:
                self.conn.sendall(bytes("4003", 'utf-8'))

    def initialize(self):
        self.home = os.path.join(setting.USER_HOME, self.username)
        self.current_dir = self.home

    def cmd(self, client_str):
        action, command = client_str.split(" ", 1)
        self.command_list = command.split(" ")
        if self.command_list[0] == "ls" or self.command_list[0] == "dir":
            if len(self.command_list) == 2:
                #判断ls是否带有路径，如果有则拼接到当前目录下
                self.command_list[1] = os.path.join(self.current_dir, self.command_list[1])
            else:
                #如果未带有参数，则直接列出当列目录下的文件
                self.command_list.append(self.current_dir)

        if self.command_list[0] == 'cd':
            if self.command_list[1]:
                if self.command_list[1] == "/":
                    #判断cd参数为/，则返回到home目录
                    self.current_dir = self.home
                else:
                    self.current_dir = os.path.join(self.current_dir, self.command_list[1])
                self.command_list[1] = self.current_dir
        try:
            execut_result = subprocess.check_output(self.command_list, shell=True)
            #execut_result = execut_result.decode('cp936').encode('utf-8')
        except Exception as e:
            execut_result = bytes('error cmd', 'utf-8')

        data_info = "info %d" % len(execut_result)
        self.conn.sendall(bytes(data_info, "utf-8"))
        ack = str(self.conn.recv(1024), "utf-8")
        print(execut_result)
        if ack == "ack":
            self.conn.sendall(bytes(execut_result))

    def post(self, client_str):
        #获取数据信息
        data_info = client_str.split(" ")
        command, src, dest, data_size = data_info
        s_file_name = os.path.split(src)[1]
        #获取相对路径和文件名
        relative_dir, n_file_name = os.path.split(dest)
        dest_dir = os.path.join(self.current_dir, relative_dir.lstrip("/"))

        #判断是否指定目标文件名，默认使用源文件名
        if not n_file_name:
            n_file_name = s_file_name
        new_file = os.path.join(dest_dir, n_file_name)
        has_recv = 0
        #判断目标文件是否存
        if os.path.isdir(dest_dir):
            if os.path.exists(new_file):
                self.conn.sendall(bytes("2003", "utf-8"))
                ack = str(self.conn.recv(1024), "utf-8")
                if ack == "2004":
                    has_recv = os.stat(new_file).st_size
                    self.conn.sendall(bytes(str(has_recv), "utf-8"))
                    f = open(new_file, 'ab')
                else:
                    f = open(new_file, 'wb')
            else:
                self.conn.sendall(bytes("2002", "utf-8"))
                f = open(new_file, "wb")

        #开始接收数据
            while int(data_size) > has_recv:
                data = self.conn.recv(1024)
                f.write(data)
                print("has_recv", has_recv)
                has_recv += len(data)
                print("data_size", data_size)
            f.close()
        else:
            print("目录不存在")
            self.conn.sendall(bytes("3000", "utf-8"))

    def get(self):
        pass

    @staticmethod
    def get_all_user():
        obj = []
        try:
            for file in os.listdir(setting.DB_DIR):
                obj.append(pickle.load(open(os.path.join(setting.DB_DIR, file), 'rb')))
            return obj
        except EOFError:
            return None


if __name__ == "__main__":
    MultiServer()








